#include "stdafx.h"
#include "Plugin.h"
#include "PluginManager.h"

SmartPtr <System_PluginManager> m_pSystem_PluginManager;

System_PluginManager :: System_PluginManager()
: Console_Subscriber("PluginManager")
{

}

System_PluginManager :: ~System_PluginManager()
{
	Plugs::iterator it = mPlugins.begin();
	for(; it != mPlugins.end(); it++)
	{
		if(!UnloadPlugin(it->first))
		{
			WriteCommandLine("Error Unloading stuff");
		}
	}
	mPlugins.clear();
}

void System_PluginManager :: Parse(const std :: string & Input)
{
	size_t index = Input.find_first_of(" ");

	std::string Header	=	System_Utility::LowerCase(Input.substr(0, index));
	std::string Content =	System_Utility::LowerCase(Input.substr(index + 1, Input.size()));

	if(Header == "check")
	{
		Plugs::iterator it = mPlugins.find(Content);
		if(it != mPlugins.end())
			g_pSystem_Console->FeedTextLog("DLL found in current context");
		else
			g_pSystem_Console->FeedTextLog("DLL not found in current context");
	}
	else
		g_pSystem_Console->FeedTextLog("Syntax Error : please use PluginManager check pluginname");
}

System_Plugin * System_PluginManager :: LoadPlugin(std::string ExtensionName)
{
	ExtensionName = System_Utility::LowerCase(ExtensionName);
	Plugs::iterator it = mPlugins.find(ExtensionName);
	if(it != mPlugins.end())
	{
		WriteCommandLine("Warning : Indentical DLL loaded %s", ExtensionName.c_str());
		return it->second.Plug;
	}
	PluginContainer	Container;
	Container.DLLModule = LoadLibraryA(ExtensionName.c_str());
	if(Container.DLLModule == NULL)
	{
		WriteCommandLine("Error : Problem loading DLL %s ", ExtensionName.c_str());
		return NULL;
	}	
	typedef System_Plugin * ( * Function) (std::string, int, int);

	Function Reference = (Function)GetProcAddress(Container.DLLModule, "GetReference");
	if(!Reference)
	{
		WriteCommandLine("Error : Problem in GetReference in DLL %s ", ExtensionName.c_str());
		FreeLibrary(Container.DLLModule);
		return NULL;
	}
	std::string Directory;
	size_t len = ExtensionName.length();
	int count = static_cast<int>(len) - 1;
	for(count;  count > -1 && ExtensionName[count]; count--)
		if(ExtensionName[count] == *"/") break;
	
	for(size_t i = 0; i < static_cast<size_t>(count + 1); i++)
		Directory.push_back(ExtensionName[i]);
	Directory = Directory.c_str();
	
	Container.Plug = Reference(Directory, APP_WIDTH, APP_HEIGHT);
	it = mPlugins.insert(mPlugins.begin(), std::pair<std::string, PluginContainer>(ExtensionName, Container));
	Container.Plug = NULL;
	return it->second.Plug;
}

bool System_PluginManager :: UnloadPlugin(std::string ExtensionName)
{
	ExtensionName = System_Utility::LowerCase(ExtensionName);
	Plugs::iterator it = mPlugins.find(ExtensionName);
	if(it == mPlugins.end())	// Not Found
		return false;

	typedef void ( * Function)(System_Plugin *);
	Function Reference =  (Function)GetProcAddress(it->second.DLLModule, "RemoveReference");
	Reference(it->second.Plug);

	FreeLibrary(it->second.DLLModule);
	it->second.DLLModule = NULL;
	it->second.Plug = NULL;
	mPlugins.erase(it);
	
	WriteCommandLine("DLL Successfully Removed %s", ExtensionName.c_str());
	Reference = NULL;
	return true;			
}


bool System_PluginManager :: UnloadAllPlugin()
{
	Plugs::iterator it = mPlugins.begin();
	for(; it != mPlugins.end(); it++)
	{
		typedef void ( * Function)(System_Plugin *);
		Function Reference =  (Function)GetProcAddress(it->second.DLLModule, "RemoveReference");
		it->second.Plug->Deinitialize();
		Reference(it->second.Plug);

		if(FreeLibrary(it->second.DLLModule))
		{
			it->second.DLLModule = NULL;
			it->second.Plug = NULL;
			WriteCommandLine("DLL Successfully Removed %s", it->first.c_str());
			continue;
		}
		WriteCommandLine("ERROR : DLL Removal Error %s", it->first.c_str());
	}
	mPlugins.clear();
	return true;			
}